

#include "../../Command.h"

#include "../../engine.h"

#include "../../User.h"
#include "../../NLogic/Static.h"
#include "../../NLogic/Battle.h"
#include "../../NLogic/SocialInfo.h"
#include "../../Proxy.h"
//#include "../../NLogic/Function.h"


namespace ProjectZ { namespace NCommand {

static void SendAckFail(User * pUser, int ack)
{
	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	* pAck << static_cast<int16_t>(ack);
	pAck->MakePacket(CMD_SC_PK_CANCEL_INVITATION_PARTY);
	pUser->Send(pAck);
}

void SetRandomPartners(User *pChief, NLogic::Party * pParty)
{
	int inviteCount = 0;

	NLogic::Space * pSpace = pChief->_getWorldSpace();
	if (NULL == pSpace)
	{
		NLogic::NFunction::SendExceptionNoSpace(pChief);
		return;
	}


	auto cUserIter = NProxy::GetUserTree().begin();

	for ( ; cUserIter != NProxy::GetUserTree().end() ; ++cUserIter )
	{
		User * pTarget = cUserIter->second;

		if(NULL == pTarget->GetSpace())
			continue;

		int levelGap = 0;
		if( pChief->GetCharacterInfo().level >= pTarget->GetCharacterInfo().level )
			levelGap = pChief->GetCharacterInfo().level - pTarget->GetCharacterInfo().level;
		else
			levelGap = pTarget->GetCharacterInfo().level - pChief->GetCharacterInfo().level;

		if( 10 < levelGap )
			continue;

		if (pTarget->GetSpace()->GetData()._spaceType != NLogic::Space::SpaceType::WORLD)
			continue;

		if (NULL != pTarget && pTarget->GetEnumState() == User::EnumState::__NONE__
			&& pTarget->GetSocialInfo()->GetData()->_invite_blocked >= static_cast<int>(NLogic::SocialInfo::EnumInviteState::BATTLE_ROYAL_ON)
			&& true == pTarget->EndBattle_afterEffect() )
		{
			DEBUGLOG("%s pChief_user_seq_[%d] pTarget_[%d], party_seq_[%d]", __FUNCTION__,
					pChief->GetUserSeq(), pTarget->GetUserSeq(), pChief->GetSpace()->GetData()._index);

			pTarget->SetEnumState(User::EnumState::BATTLE_ROYAL_PARTY_WAIT);
			pParty->EnterUser(pTarget);
			// player 인덱스 생성
			pTarget->GetBattle()->GetData()._inviteCount = inviteCount++;

			if ( static_cast<size_t>(MAX_PK_INVITE) <= pParty->GetAllUserTree().size())
				return;
		}
	}
}

bool CanMakePK(User *pChief)
{
	int inviteCount = 0;

	NLogic::Space * pSpace = pChief->_getWorldSpace();
	if (NULL == pSpace)
	{
		NLogic::NFunction::SendExceptionNoSpace(pChief);
		return false;
	}

	auto cUserIter = NProxy::GetUserTree().begin();

	for ( ; cUserIter != NProxy::GetUserTree().end() ; ++cUserIter )
	{
		User * pTarget = cUserIter->second;

		if(NULL == pTarget->GetSpace())
			continue;

		int levelGap = 0;
		if( pChief->GetCharacterInfo().level >= pTarget->GetCharacterInfo().level )
			levelGap = pChief->GetCharacterInfo().level - pTarget->GetCharacterInfo().level;
		else
			levelGap = pTarget->GetCharacterInfo().level - pChief->GetCharacterInfo().level;

		if( 10 < levelGap )
			continue;

		if (pTarget->GetSpace()->GetData()._spaceType != NLogic::Space::SpaceType::WORLD)
			continue;

		if (NULL != pTarget && pTarget->GetEnumState() == User::EnumState::__NONE__
			&& pTarget->GetSocialInfo()->GetData()->_invite_blocked >= static_cast<int>(NLogic::SocialInfo::EnumInviteState::BATTLE_ROYAL_ON)
			&& true == pTarget->EndBattle_afterEffect() )
		{
			DEBUGLOG("%s pChief_user_seq_[%d] pTarget_[%d], party_seq_[%d]", __FUNCTION__,
					pChief->GetUserSeq(), pTarget->GetUserSeq(), pChief->GetSpace()->GetData()._index);

			inviteCount++;

			if ( MIN_PK_INVITE <= inviteCount)
				return true;
		}
	}

	return false;
}

void SendInvite(NLogic::Party * pParty, User *pChief, int opp_gid)
{
	if ( static_cast<size_t>(MAX_PK_INVITE) <= pParty->GetAllUserTree().size())
		return;

	int inviteCount = 0;

	NLogic::Space * pSpace = pChief->_getWorldSpace();
	if (NULL == pSpace)
	{
		NLogic::NFunction::SendExceptionNoSpace(pChief);
		return;
	}

	User * pTarget = NProxy::GetUser(opp_gid);

	if(NULL == pTarget)
		return;

	if(NULL == pTarget->GetSpace())
		return;

	int levelGap = 0;
	if( pChief->GetCharacterInfo().level >= pTarget->GetCharacterInfo().level )
		levelGap = pChief->GetCharacterInfo().level - pTarget->GetCharacterInfo().level;
	else
		levelGap = pTarget->GetCharacterInfo().level - pChief->GetCharacterInfo().level;

	if( 10 < levelGap )
		return;

	if (pTarget->GetSpace()->GetData()._spaceType != NLogic::Space::SpaceType::WORLD)
		return;

	if (NULL != pTarget && pTarget->GetEnumState() == User::EnumState::__NONE__ &&
			pTarget->GetSocialInfo()->GetData()->_invite_blocked >= static_cast<int>(NLogic::SocialInfo::EnumInviteState::BATTLE_ROYAL_ON)
			&& true == pTarget->EndBattle_afterEffect() )
	{
		DEBUGLOG("%s pChief_user_seq_[%d] pTarget_[%d], party_seq_[%d]", __FUNCTION__,
				pChief->GetUserSeq(), pTarget->GetUserSeq(), pChief->GetSpace()->GetData()._index);

		pTarget->SetEnumState(User::EnumState::BATTLE_ROYAL_PARTY_WAIT);
		pParty->EnterUser(pTarget);
		// player 인덱스 생성
		pTarget->GetBattle()->GetData()._inviteCount = inviteCount++;
	}
}

void Command::CS_PK_SEND_INVITATION(User * pUser, ::Network::Packet * pPacket)
{
/*
	C -> S
	CS_PK_SEND_INVITATION							0x1415
	{
		u8 u8type;	// 0: 랜덤 1: 초대 - 랜덤방식도 모르는 사람 초대방식으로 변경됨

		u8 u8count; // 랜덤일시 카운트 0
		{
			u32 u32gid;	// 친구 아이디
		}
	}

	S -> C 랜덤일 경우 다른 유저 초대하기
	/// 초대 받기 : 친구가 나를 초대함
	SC_PK_RECV_INVITATION 							0x1417
	{
		u8  u8pk_GroupType;	// 0: 4명 초대 1: 3명초대
		u32 u32pk_seq;		// pk session seq

		///
		u32 u32owner_gid;	// 초대한 방장의 gid  // SC_REQ_SOCIAL_INFO 로 정보 요청
	}

	S -> C 친구 초대일 경우
	SC_PK_SEND_INVITATION							0x1416
	{
		u8  u8pk_GroupType;	// 0: 4명 초대 1: 3명초대
		u32 u32pk_seq;		// pk session seq
	}
*/
	STRESSLOG("%s", __FUNCTION__);

	NLogic::Space * pWorld = pUser->GetSpace();
	if ( NULL == pWorld )
	{
		NLogic::NFunction::SendExceptionNoSpace(pUser);
		DEBUGLOG("%s Space is NULL", __FUNCTION__);
		return;
	}

	if (false == pUser->EndBattle_afterEffect())
	{
		::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
		* pAck << static_cast<int16_t>(ACK_BATTLE_AFTEREFFECT);
		pAck->MakePacket(CMD_SC_PK_CANCEL_INVITATION_PARTY);
		pUser->Send(pAck);
		STRESSLOG("CS_REQ_DUNGEON_CREATE_SINGLE ACK");

		return;
	}

	if ( User::EnumState::__NONE__ != pUser->GetEnumState() )
	{
		::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
		* pAck << static_cast<int16_t>(ACK_OK);
		pAck->MakePacket(CMD_SC_PK_CANCEL_INVITATION_PARTY);
		pUser->Send(pAck);
		DEBUGLOG("%s User::EnumState::__NONE__ != pUser->GetEnumState()", __FUNCTION__);
		return;
	}

	auto & pkRoomTree = NLogic::Static::Instance().GETPKROOMTREE();

	if (MAX_NEW_PK_ROOM <= static_cast<int>(pkRoomTree.size()))
	{
		DEBUGLOG("%s (MAX_NEW_PK_ROOM) <= pkRoomVector.size()", __FUNCTION__);
		SendAckFail(pUser, ACK_PVP_PK_OVER_ROOM_COUNT);
		return;
	}

	NLogic::IndexerPK * pPKIndex = NLogic::Static::InstancePtr()->GETPKINDEXPOOL()->NEW();
	if (NULL == pPKIndex)
	{
		DEBUGLOG("%s : pPKIndex is NULL!!", __FUNCTION__);
		SendAckFail(pUser, ACK_UNKNOWN_ERROR);
		return;
	}

	PREPARE_PACKET;

	uint8_t type = 0, count = 0;
	*pPacket >> type >> count;

	// 월드에서 나감
	pUser->SetEnumState(User::EnumState::BATTLE_ROYAL_PARTY_WAIT);
	pWorld->LeaveUser(pUser);

	// 파티 생성
	NLogic::Party * pParty = NLogic::Static::Instance().GETPARTYPOOL()->NEW();
	pParty->Open(pUser);
	pParty->AddAcceptUserTree(pUser);

	// PK Space 설정
	NLogic::Space::Data clsData;
	clsData._maxUser = MAX_PK_INVITE;
	clsData._spaceType = NLogic::Space::SpaceType::BATTLEROYAL;

	// PK Space 생성
	NLogic::Space * pBattleRoyal = NLogic::Static::Instance().GETSPACEPOOL()->NEW();
	pBattleRoyal->Open(pUser, clsData);
	// PK Space 에 파티 설정
	pBattleRoyal->SetParty(pParty);

	// Indexer 설정
	pBattleRoyal->SetPKIndexer(pPKIndex);

	// PK Space 에 입장
	pBattleRoyal->EnterUser(pUser);

	pkRoomTree[pPKIndex->GetIndex()] = pBattleRoyal;

	if( type == 0 )		// random
	{
		if ( false == CanMakePK(pUser))
		{
			::Network::Packet * pCancelAck = ::Network::GETPACKETPOOL()->SEND_NEW();
			*pCancelAck << static_cast<uint16_t>(ACK_OK);
			pCancelAck->MakePacket(CMD_SC_PK_CANCEL_INVITATION_PARTY);
			pUser->Send(pCancelAck);

			pUser->SetEnumState(User::EnumState::BATTLE_ROYAL_END);
			pBattleRoyal->LeaveUser(pUser);
			return;
		}
		SetRandomPartners(pUser, pParty);
	}
	else if( type == 1 )	// friend
	{
		for( int i=0 ; i<count ; i++ )
		{
			int opp_gid = 0;
			*pPacket >> opp_gid;
			SendInvite(pParty, pUser, opp_gid);
		}
	}

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();

	int groupType = pParty->GetAllUserTree().size() == 4 ? 0 : 1;
	*pAck << static_cast<uint8_t>(groupType);
	*pAck << pBattleRoyal->GetData()._index;
	pAck->MakePacket(CMD_SC_PK_SEND_INVITATION);
	pUser->Send(pAck);

	::Network::Packet * pTargetAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	*pTargetAck << static_cast<uint8_t>(groupType);
	*pTargetAck << pUser->GetSpace()->GetData()._index << pUser->GetUserSeq();
	pTargetAck->MakePacket(CMD_SC_PK_RECV_INVITATION);

	std::for_each(pParty->GetAllUserTree().begin(), pParty->GetAllUserTree().end(), [&](const std::pair<int, User *> & pair) {
		if(pUser->GetUserSeq() != pair.first)
		{
			pair.second->SendOneshotEncrypt(pTargetAck, 1);
		}
	} );
	::Network::GETPACKETPOOL()->SEND_DEL(pTargetAck);

	pParty->SetState(NLogic::Party::State::PK_ACCEPT_WAIT);
}

} /*NCommand*/ }  /*ProjectZ*/
